﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FitnessMVC.Data;
using Moq;

namespace FitnessMVC.Test.Fakes
{
    public class FakeFitnessData
    {
        private Guid _appId = new Guid("bd167fb0-1e0d-11de-8c30-0800200c9a66");

        public List<User> Users { get; private set; }
        public List<Membership> Memberships { get; private set; }
        public List<UserProfile> Profiles { get; private set; }
        public List<UserBuddy> UserBuddies { get; private set; }

        public User GetFakeUser()
        {
            return new User()
            {
                ApplicationId = _appId,
                IsAnonymous = false,
                LastActivityDate = DateTime.Now.Subtract(TimeSpan.FromDays(1)),
                LoweredUserName = "test" + this.Users.Count+1,
                UserId = Guid.NewGuid(),
                UserName = "test" + this.Users.Count+1
            };
        }

        public UserProfile GetFakeUserProfile(Guid userId)
        {
            return new UserProfile()
            {
                FirstName = "Fake",
                LastName = "User",
                AboutMe = "Just a fake user trying to get by...",
                BirthDate = new DateTime(1980, 1, 21),
                Hometown = "Boston, MA",
                MemberSince = new DateTime(2009, 3, 31),
                ProfilePicID = 1,
                Sex = 'm',
                IsPublic = true,
                UserID = userId
            };
        }

        public void SetupFakeData()
        {
            Users = new List<User>();
            Memberships = new List<Membership>();
            Profiles = new List<UserProfile>();
            UserBuddies = new List<UserBuddy>();

            // Create some fake users.
            Users.Add(new User()
            {
                ApplicationId = _appId,
                IsAnonymous = false,
                LastActivityDate = DateTime.Now.Subtract(TimeSpan.FromDays(1)),
                LoweredUserName = "test1",
                UserId = Guid.NewGuid(),
                UserName = "test1"
            });

            Users.Add(new User()
            {
                ApplicationId = _appId,
                IsAnonymous = false,
                LastActivityDate = DateTime.Now.Subtract(TimeSpan.FromDays(2)),
                LoweredUserName = "test2",
                UserId = Guid.NewGuid(),
                UserName = "test2"
            });

            Users.Add(new User()
            {
                ApplicationId = _appId,
                IsAnonymous = false,
                LastActivityDate = DateTime.Now.Subtract(TimeSpan.FromDays(3)),
                LoweredUserName = "test3",
                UserId = Guid.NewGuid(),
                UserName = "test3"
            });

            int i = 1;
            foreach (var user in Users)
            {
                // Create some fake membership information.
                Memberships.Add(new Membership()
                {
                    ApplicationId = _appId,
                    UserId = user.UserId,
                    Comment = "Some test user " + i.ToString(),
                    CreateDate = DateTime.Now.Subtract(TimeSpan.FromDays(30)),
                    Email = String.Format("test{0}@test.com", i),
                    IsApproved = true,
                    IsLockedOut = false,
                    LoweredEmail = String.Format("test{0}@test.com", i)
                });

                // Create some fake profile information.
                Profiles.Add(new UserProfile()
                {
                    ProfileID = i,
                    ProfilePicID = 1,
                    UserID = user.UserId,
                    FirstName = "Test" + i,
                    LastName = "User",
                    AboutMe = "I'm just a test user for testing.",
                    Hometown = "Boston, MA",
                    BirthDate = new DateTime(1985, 1, 1),
                    MemberSince = new DateTime(2009, 3, 30),
                    Sex = 'm',
                    // Every third profile is private.
                    IsPublic = i % 3 == 0 ? false : true
                });

                ++i;
            }

            // Create some fake buddies
            UserBuddies.Add(new UserBuddy()
            {
                BuddyId = 1,
                User1Id = Users[0].UserId,
                LeftUser = Users[0],
                User2Id = Users[1].UserId,
                RightUser = Users[1],
            });

            UserBuddies.Add(new UserBuddy()
            {
                BuddyId = 2,
                User1Id = Users[1].UserId,
                LeftUser = Users[1],
                User2Id = Users[2].UserId,
                RightUser = Users[2],
            });
        }

        public static FakeFitnessData GetFakeData()
        {
            FakeFitnessData data = new FakeFitnessData();
            data.SetupFakeData();

            return data;
        }

        public IFitnessRepository GetMockFitnessRepository()
        {
            var data = new Mock<IFitnessRepository>();

            // Mock Get All User Profiles
            data.Setup(x => x.GetAllProfiles()).Returns(this.Profiles.AsQueryable());

            // Mock Get User By UserId
            data.Setup(x => x.GetUserByUserId(It.IsAny<Guid>()))
                .Returns((Guid uId) => this.Users.FirstOrDefault(u => u.UserId == uId));                

            // Mock Are Users Buddies
            data.Setup(x => x.AreUsersBuddies(It.IsAny<string>(), It.IsAny<string>()))
                .Returns(
                (string user1, string user2) => 
                    this.GetUserBuddies(user1).Any(y => y.UserName == user2)
                );

            data.Setup(x => x.AddUserProfile(It.IsAny<UserProfile>()))
                .Callback((UserProfile y) => this.AddProfile(y));
                
                

            // Mock GetUserProfile By UserName.
            data.Setup(x => x.GetUserProfile(It.IsAny<string>()))
                .Returns((string uName) => this.GetUserProfileByUserName(uName));

            // Mock GetUserBuddies
            data.Setup(x => x.GetUserBuddies(It.IsAny<string>()))
                .Returns((string uName) => this.GetUserBuddies(uName));

            return data.Object;
        }

        private void AddProfile(UserProfile up)
        {
            if (up.User != null)
            {
                if (!Users.Any(u => u.UserId == up.User.UserId))
                    Users.Add(up.User);
            }
            else
            {
                var newUser = GetFakeUser();
                Users.Add(newUser);
                up.User = newUser;
                up.UserID = newUser.UserId;
            }

            up.ProfileID = Profiles.Count + 1;
            Profiles.Add(up);
        }

        public UserProfile GetUserProfileByUserName(string userName)
        {
            return Profiles.FirstOrDefault(
                x => x.UserID == Users.FirstOrDefault(
                    y => y.UserName == userName).UserId
                    );
        }

        private IQueryable<User> GetUserBuddies(string uName)
        {
            return (from buddy in UserBuddies
                    let user = (from u in Users
                                where u.UserName == uName
                                select u).First()
                    where buddy.User1Id == user.UserId ||
                          buddy.User2Id == user.UserId
                    select buddy.User1Id == user.UserId ? buddy.RightUser : buddy.LeftUser).AsQueryable();
        }

        
        
    }
}
